package com.hsmpay.utils;

import com.hsmpay.utils.system.PbkConfig;
import it.sauronsoftware.base64.Base64;
import org.apache.log4j.Logger;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import sun.misc.BASE64Decoder;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * 原来在用mac 系统中自带的openssl生成的密钥对文件是X509编码格式的。而我们JAVA所需的私钥文件是PKCS#8编码格式的。。所以要将在mac 系统中生成的私钥文件转下码就行了
 * 而安卓需要 添加Cipher cipher = Cipher.getInstance("RSA", "BC");
 * 
 * 三个平台使用
 * @author Administrator
 *
 */
public class RSAObjectC {

	private static Logger log = Logger.getLogger(RSAObjectC.class);
	private static String DEFAULT_PUBLIC_KEY = PbkConfig.getAttribute("JIAMI_PUB_KEY").trim();
//		"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCskYbd5kRYZATRQgEucd1VVZh6" + "\r" +
//		"GWyT+95fyuNG5kZm4AyLvJaeUd2j22oWH1aKPj1KVlCsZjw+0sw54fIN8ZWEuIbn" + "\r" +
//		"1oeSKZzYR8aCKqCViGbn9FOpO2qPfZm2T2UnV5o6Zq5471l2LuNiwNLTDqbuw8Um" + "\r" +
//		"njj66o/SYEOWuXBWawIDAQAB" + "\r";
//		"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCvYLXcmTcjYmcq4XN4fON5OE9v" + "\r" +
//		"vQCbgMp054aEhL/DzuQeQNSr36L9UBdtjA3fRoGU26tE65tRAmzy2XYeh10wJOTr" + "\r" +
//		"QwRD2mE7hLWZAPla70KFBkWPfCYn6EMn3vQ917xjY8kklL3SrsDGRuFeW1ugz8xC" + "\r" +
//		"bJCHcUkDW0b60WBkrQIDAQAB" + "\r" ;


	private static final String DEFAULT_PRIVATE_KEY=
		"MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKyRht3mRFhkBNFC" + "\r" +
		"AS5x3VVVmHoZbJP73l/K40bmRmbgDIu8lp5R3aPbahYfVoo+PUpWUKxmPD7SzDnh" + "\r" +
		"8g3xlYS4hufWh5IpnNhHxoIqoJWIZuf0U6k7ao99mbZPZSdXmjpmrnjvWXYu42LA" + "\r" +
		"0tMOpu7DxSaeOPrqj9JgQ5a5cFZrAgMBAAECgYEApvJa0U21jPWmG3OJhQ8vGyEl" + "\r" +
		"0+nIuxmNtoqnea3JKjlSqdUWua9lhuH8Lc6/gBpaXRJIFaEKY5S3cr/91jODez3q" + "\r" +
		"Grngl/D/AMsx/NAaj30XzUAf3OObKWVTZdNERUUuxafeLM8xNbhUhS0F8AMdc8z3" + "\r" +
		"O/u+w3HTTJ8gqdtpWuECQQDW2MMV9c/oH6GsDk9l9UCOmoNHFmQkPLV90/ws35Oj" + "\r" +
		"tsqpYv4KP4ZbUaw7pkJkCPHzHfYAI0xw1C67GQUrGKtZAkEAzZ+a66FkxJcext0Q" + "\r" +
		"Dz+lu1JMkE79zXVET310h6JY/xAKuqOCAw+pQcQQv8XuEi3OxnMZcfD1KFh0Zuxu" + "\r" +
		"mutLYwJBANFtgt2JPB09mE8rs+HjbAaWP5mwDfX058W8OnlTh4tyx6LOSGyc989U" + "\r" +
		"kdujedwhjBg9AGup/P2PF+5xuUQFTCECQBwb6HKzsnHJctSenbZn7gEIhBzqH3n5" + "\r" +
		"wOfY75gnEmFz0POorHo8ptettNhyd1QW3QB19ZGE7g6g4PC8+3XEGp8CQDHOTLDo" + "\r" +
		"UxB7dO3W5q2DFFjbbWNB/Fw2DRMbh6xYLrLNXoXRUByjCbKtDLuRF2PnUlMIEaV/" + "\r" +
		"EB011IK3iTQMLYc=" + "\r";
//		"MIICXQIBAAKBgQCvYLXcmTcjYmcq4XN4fON5OE9vvQCbgMp054aEhL/DzuQeQNSr" + "\r" +
//		"36L9UBdtjA3fRoGU26tE65tRAmzy2XYeh10wJOTrQwRD2mE7hLWZAPla70KFBkWP" + "\r" +
//		"fCYn6EMn3vQ917xjY8kklL3SrsDGRuFeW1ugz8xCbJCHcUkDW0b60WBkrQIDAQAB" + "\r" +
//		"AoGBAJdFA5hTT4vlxLbn34F9t3dHar0meO+oFvje+tgy6HUsbvbpVIcrTprQCmUi" + "\r" +
//		"+JQtbHfJQeEgl8c4IGEX0RpkB6uhm0R+4s/lTqhnhEJh+ULdacYV8vaLt7e0kyjg" + "\r" +
//		"7zM4o80LJR0wk1hnZqMoQyH4+WVf7rc6/sCUjfnynZb5/FjBAkEA1f5iKt2u6Qtv" + "\r" +
//		"TpgeGvijtCxZy2hoPtRizF/maAOpXt+mcKxd3YbPMorcaqrtp3+kDIM4KfFyCFFL" + "\r" +
//		"UiszOEidVwJBANHNzJStAABXQdugzftA0hVHIsDfj3FH5mJ8l4c04/9QyvBr79jV" + "\r" +
//		"cTaCPPn3EGva+vtHMjbIjPQYxGxqpRKqR5sCQQCFse3BHEk4HkXHU7CTZz5XxdHA" + "\r" +
//		"DJX8kxK63zuDRq5dsNs6z+XBDoWK7Uiyd+IM4OksTBsd0VROMAQf7Q+OHYf3AkBc" + "\r" +
//		"JXdlFVaaz7gtLkNJxv5+OfAZphbqOhoFx5MF30UELgfz8HQ3WAeRWUJOxyR/On5h" + "\r" +
//		"PrPfO9Ysn3Ql6fD2cbNhAkAbKyAD0zl4QUHtcmwKyhTJzJbw/Jvm32orVMoSB5EB" + "\r" +
//		"2yYVTcDY/Nw6FUz8ej82sKxxHXGvfPVVr4vygppecvEm" + "\r";


	/**
	 * 私钥
	 */
	private RSAPrivateKey privateKey;

	/**
	 * 公钥
	 */
	private RSAPublicKey publicKey;
	
	/**
	 * 字节数据转字符串专用集合
	 */
	private static final char[] HEX_CHAR= {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
	

	/**
	 * 获取私钥
	 * @return 当前的私钥对象
	 */
	public RSAPrivateKey getPrivateKey() {
		return privateKey;
	}

	/**
	 * 获取公钥
	 * @return 当前的公钥对象
	 */
	public RSAPublicKey getPublicKey() {
		return publicKey;
	}

	/**
	 * 随机生成密钥对
	 */
	public void genKeyPair(){
		KeyPairGenerator keyPairGen= null;
		try {
			keyPairGen= KeyPairGenerator.getInstance("RSA");
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		keyPairGen.initialize(1024, new SecureRandom());
		KeyPair keyPair= keyPairGen.generateKeyPair();
		this.privateKey= (RSAPrivateKey) keyPair.getPrivate();
		this.publicKey= (RSAPublicKey) keyPair.getPublic();
	}

	/**
	 * 从文件中输入流中加载公钥
	 * @param in 公钥输入流
	 * @throws Exception 加载公钥时产生的异常
	 */
	public void loadPublicKey(InputStream in) throws Exception{
		try {
			BufferedReader br= new BufferedReader(new InputStreamReader(in));
			String readLine= null;
			StringBuilder sb= new StringBuilder();
			while((readLine= br.readLine())!=null){
				if(readLine.charAt(0)=='-'){
					continue;
				}else{
					sb.append(readLine);
					sb.append('\r');
				}
			}
			loadPublicKey(sb.toString());
		} catch (IOException e) {
			throw new Exception("公钥数据流读取错误");
		} catch (NullPointerException e) {
			throw new Exception("公钥输入流为空");
		}
	}


	/**
	 * 从字符串中加载公钥
	 * @param publicKeyStr 公钥数据字符串
	 * @throws Exception 加载公钥时产生的异常
	 */
	public void loadPublicKey(String publicKeyStr) throws Exception{
		try {
			log.debug("公钥：#"+new String(Base64.encode(publicKeyStr.getBytes("UTF-8")),"UTF-8"));
			BASE64Decoder base64Decoder= new BASE64Decoder();
			byte[] buffer= base64Decoder.decodeBuffer(publicKeyStr);
			KeyFactory keyFactory= KeyFactory.getInstance("RSA");
			X509EncodedKeySpec keySpec= new X509EncodedKeySpec(buffer);
			publicKey= (RSAPublicKey) keyFactory.generatePublic(keySpec);
		} catch (NoSuchAlgorithmException e) {
			throw new Exception("无此算法");
		} catch (InvalidKeySpecException e) {
			throw new Exception("公钥非法");
		} catch (IOException e) {
			throw new Exception("公钥数据内容读取错误");
		} catch (NullPointerException e) {
			throw new Exception("公钥数据为空");
		}
	}

	/**
	 * 从文件中加载私钥
	 * @param keyFileName 私钥文件名
	 * @return 是否成功
	 * @throws Exception 
	 */
	public void loadPrivateKey(InputStream in) throws Exception{
		try {
			BufferedReader br= new BufferedReader(new InputStreamReader(in));
			String readLine= null;
			StringBuilder sb= new StringBuilder();
			while((readLine= br.readLine())!=null){
				if(readLine.charAt(0)=='-'){
					continue;
				}else{
					sb.append(readLine);
					sb.append('\r');
				}
			}
			loadPrivateKey(sb.toString());
		} catch (IOException e) {
			throw new Exception("私钥数据读取错误");
		} catch (NullPointerException e) {
			throw new Exception("私钥输入流为空");
		}
	}

	public void loadPrivateKey(String privateKeyStr) throws Exception{
		try {
			log.debug("私钥：#"+new String(Base64.encode(privateKeyStr.getBytes("UTF-8")),"UTF-8"));
			BASE64Decoder base64Decoder= new BASE64Decoder();
			byte[] buffer= base64Decoder.decodeBuffer(privateKeyStr);
			PKCS8EncodedKeySpec keySpec= new PKCS8EncodedKeySpec(buffer);
			KeyFactory keyFactory= KeyFactory.getInstance("RSA");
			privateKey= (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
		} catch (NoSuchAlgorithmException e) {
			throw new Exception("无此算法");
		} catch (InvalidKeySpecException e) {
			throw new Exception("私钥非法");
		} catch (IOException e) {
			throw new Exception("私钥数据内容读取错误");
		} catch (NullPointerException e) {
			throw new Exception("私钥数据为空");
		}
	}

	/**
	 * 加密过程
	 * @param publicKey 公钥
	 * @param plainTextData 明文数据
	 * @return
	 * @throws Exception 加密过程中的异常信息
	 */
	public byte[] encrypt(RSAPublicKey publicKey, byte[] plainTextData) throws Exception{
		if(publicKey== null){
			throw new Exception("加密公钥为空, 请设置");
		}
		Cipher cipher= null;
		try {
			cipher= Cipher.getInstance("RSA", new BouncyCastleProvider());
			cipher.init(Cipher.ENCRYPT_MODE, publicKey);
			byte[] output= cipher.doFinal(plainTextData);
			return output;
		} catch (NoSuchAlgorithmException e) {
			throw new Exception("无此加密算法");
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
			return null;
		}catch (InvalidKeyException e) {
			throw new Exception("加密公钥非法,请检查");
		} catch (IllegalBlockSizeException e) {
			throw new Exception("明文长度非法");
		} catch (BadPaddingException e) {
			throw new Exception("明文数据已损坏");
		}
	}
	
	/**
	 * 加密过程 没有用安卓补位
	 * @param publicKey 公钥
	 * @param plainTextData 明文数据
	 * @return
	 * @throws Exception 加密过程中的异常信息
	 */
	public byte[] encryptNew(RSAPublicKey publicKey, byte[] plainTextData) throws Exception{
		if(publicKey== null){
			throw new Exception("加密公钥为空, 请设置");
		}
		Cipher cipher= null;
		try {
			cipher= Cipher.getInstance("RSA");
			cipher.init(Cipher.ENCRYPT_MODE, publicKey);
			byte[] output= cipher.doFinal(plainTextData);
			return output;
		} catch (NoSuchAlgorithmException e) {
			throw new Exception("无此加密算法");
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
			return null;
		}catch (InvalidKeyException e) {
			throw new Exception("加密公钥非法,请检查");
		} catch (IllegalBlockSizeException e) {
			throw new Exception("明文长度非法");
		} catch (BadPaddingException e) {
			throw new Exception("明文数据已损坏");
		}
	}

	/**
	 * 解密过程
	 * @param privateKey 私钥
	 * @param cipherData 密文数据
	 * @return 明文
	 * @throws Exception 解密过程中的异常信息
	 */
	public byte[] decrypt(RSAPrivateKey privateKey, byte[] cipherData) throws Exception{
		if (privateKey== null){
			throw new Exception("解密私钥为空, 请设置");
		}
		Cipher cipher= null;
		try {
			cipher= Cipher.getInstance("RSA", new BouncyCastleProvider());
			cipher.init(Cipher.DECRYPT_MODE, privateKey);
			byte[] output= cipher.doFinal(cipherData);
			return output;
		} catch (NoSuchAlgorithmException e) {
			throw new Exception("无此解密算法");
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
			return null;
		}catch (InvalidKeyException e) {
			throw new Exception("解密私钥非法,请检查");
		} catch (IllegalBlockSizeException e) {
			throw new Exception("密文长度非法");
		} catch (BadPaddingException e) {
			throw new Exception("密文数据已损坏");
		}		
	}
	
	/**
	 * 解密过程  没有用安卓补位
	 * @param privateKey 私钥
	 * @param cipherData 密文数据
	 * @return 明文
	 * @throws Exception 解密过程中的异常信息
	 */
	public byte[] decryptNew(RSAPrivateKey privateKey, byte[] cipherData) throws Exception{
		if (privateKey== null){
			throw new Exception("解密私钥为空, 请设置");
		}
		Cipher cipher= null;
		try {
			cipher= Cipher.getInstance("RSA");
			cipher.init(Cipher.DECRYPT_MODE, privateKey);
			byte[] output= cipher.doFinal(cipherData);
			return output;
		} catch (NoSuchAlgorithmException e) {
			throw new Exception("无此解密算法");
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
			return null;
		}catch (InvalidKeyException e) {
			throw new Exception("解密私钥非法,请检查");
		} catch (IllegalBlockSizeException e) {
			throw new Exception("密文长度非法");
		} catch (BadPaddingException e) {
			throw new Exception("密文数据已损坏");
		}		
	}

	
	/**
	 * 字节数据转十六进制字符串
	 * @param data 输入数据
	 * @return 十六进制内容
	 */
	public static String byteArrayToString(byte[] data){
		StringBuilder stringBuilder= new StringBuilder();
		for (int i=0; i<data.length; i++){
			//取出字节的高四位 作为索引得到相应的十六进制标识符 注意无符号右移
			stringBuilder.append(HEX_CHAR[(data[i] & 0xf0)>>> 4]);
			//取出字节的低四位 作为索引得到相应的十六进制标识符
			stringBuilder.append(HEX_CHAR[(data[i] & 0x0f)]);
			if (i<data.length-1){
				stringBuilder.append(' ');
			}
		}
		return stringBuilder.toString();
	}

	private RSAObjectC(){
		
	}
	public static RSAObjectC getInstance(){
		RSAObjectC rsaEncrypt= new RSAObjectC();
		//rsaEncrypt.genKeyPair();

		//加载公钥
		try {
			rsaEncrypt.loadPublicKey(RSAObjectC.DEFAULT_PUBLIC_KEY);
			log.debug("加载公钥成功");
		} catch (Exception e) {
			System.err.println(e.getMessage());
			System.err.println("加载公钥失败");
		}

		//加载私钥
		try {
			rsaEncrypt.loadPrivateKey(RSAObjectC.DEFAULT_PRIVATE_KEY);
			log.debug("加载私钥成功");
		} catch (Exception e) {
			System.err.println(e.getMessage());
			System.err.println("加载私钥失败");
		}
		return rsaEncrypt;
	}
	
	public static RSAObjectC getInstance(String publicKey,String privateKey){
		RSAObjectC rsaEncrypt= new RSAObjectC();
		//rsaEncrypt.genKeyPair();

		//加载公钥
		try {
			rsaEncrypt.loadPublicKey(publicKey);
			log.debug("加载公钥成功");
		} catch (Exception e) {
			System.err.println(e.getMessage());
			System.err.println("加载公钥失败");
		}

		//加载私钥
		try {
			rsaEncrypt.loadPrivateKey(privateKey);
			log.debug("加载私钥成功");
		} catch (Exception e) {
			System.err.println(e.getMessage());
			System.err.println("加载私钥失败");
		}
		return rsaEncrypt;
	}
}
